#include"include/allinall_object.hpp"

void basemanager::listbuffers(){
	printf("%s:\n",call);
	int i=0;
	for(i;i<name.size();++i)
		printf("%d:%s's count:%d\n",i,name[i],size[i]);
	if(!i)
		printf("you haven't add any %s in here\n",call);
}

basemanager::~basemanager(){
	for(int i=0;i<name.size();++i){
		glDeleteBuffers(size[i],id[i]);
		delete name[i];
		delete id[i];
	}
}

static size_t temp_fi=0;
bool basemanager::findname(const char*obj){
	temp_fi=name.size();
	for(int i=0;i<temp_fi;++i)
		if(!strcmp(obj,name[i])){
			temp_fi=i;
			goto ME;
		}
	if(temp_fi==name.size()){
		// printf("can't find the %s obj:%s\n",this->call,obj);
		return false;
	}
	ME:
	return true;
}
bool basemanager::checkID(size_t obj){
	if(obj>=size.size()){
		// printf("This %s_Manager only have %d %s indexs\n",this->call,name.size(),this->call);
		return false;
	}
	return true;
}
bool basemanager::checkIndex(size_t obj,GLuint index){
	if(index>=size[obj]){
		// printf("%s's range:0-%d)\n",name[obj],size[obj]-1);
		return false;
	}
	return true;
}

void basemanager::add(const char*call,GLsizei n){
	if(findname(call)){
		printf("name %s allready exist\n",call);
		return;
	}
	name.push_back(new char[32]);
	strncpy(name.back(),call,strlen(call)+1);
	id.push_back(new GLuint[n]);
	size.push_back(n);
	Gen(n,id.back());
}


void basemanager::bind(const char*type,GLuint index){
	if(findname(type))
		bind(temp_fi,index);
}

void basemanager::bind(size_t type,GLuint index){
	if(checkID(type)&&checkIndex(type,index))
		Bind(GL_ARRAY_BUFFER,*(id[type]+index));
}

/**********VBO**********/

void bufferobj::putdata(void*data,size_t size){
	// float*dasta=(float*)(data);
	// for(int i=0;i<size/4;++i)
	// 	printf("%f\n",dasta[i]);
	glBufferData(GL_ARRAY_BUFFER,size,data,GL_STATIC_DRAW);
}

bufferobj::bufferobj(){
	Gen=glGenBuffers;
	Bind=glBindBuffer;
	call="Buffer";
}

/**********VAO**********/

void __stdcall glBindVertexArray_local(GLenum a,GLuint id){
	glBindVertexArray(id);
}

arrayobj::arrayobj(){
	Gen=glGenVertexArrays;
	Bind=&glBindVertexArray_local;
	call="VertexArray";
}

void arrayobj::setline(mesh*info){
	int n=info->kofd.size();
	// printf("GL_FLOAT:%d\tGL_FALSE:%d\n",GL_FLOAT,GL_FALSE);
	for(int i=0;i<n;++i){
		// printf("glVertexAttribPointer(%d,%d,%d,%d,%d,%d)\n",i,
			// info->lofu[i],info->tofd[i],
			// info->rbil[i],
			// info->stride_byte,(int)(info->offset(i)));
		glVertexAttribPointer(i,
			info->lofu[i],info->tofd[i],
			info->rbil[i],
			info->stride_byte,info->offset(i));
		glEnableVertexAttribArray(i);
	}
}

void*mesh::offset(int n){
	size_t startpos=0;
	for(int i=0;i<n;++i)
		startpos+=lofu[i]*lofv[i];
	return (void*)startpos;
}
mesh::mesh(){
	data=(float*)malloc(0);
	stride=0;
	stride_byte=0;
}
mesh::~mesh(){
	free(data);
	for(int i=0;i<ptr.size();++i)
		free(ptr[i]);
}

void mesh::sort(){
	// vector<void*>temp_ptr=ptr;//wait to test
	vector<size_t>lenth{lofu[0]*lofv[0]};
	vector<size_t>offset{0};
	size_t full_lenth=lenth[0];
	size_t temp=lofd[0]/lofu[0];
	for(int i=1;i<kofd.size();++i){
		offset.push_back(full_lenth);
		lenth.push_back(lofu[i]*lofv[i]);
		full_lenth+=lenth[i];
		int k=lofd[i]/lofu[i];
		if(k<temp)
			temp=k;
	}
	stride_byte=full_lenth;
	temp=temp-temp%3;
	size=full_lenth*temp;
	data=(void*)realloc(data,size);
	for(int i=0;i<temp;++i)
		for(int j=0;j<lenth.size();++j)
			memcpy((char*)data+i*full_lenth+offset[j],(char*)ptr[j]+i*lenth[j],lenth[j]);
}

GLenum whichtype(char a){
	switch(a){
		case 'f':
		return GL_FLOAT;
	}
	return 0;
}